import type { VxeTableGridOptions } from './types';

import {defineComponent, h, watch} from 'vue';

import {
  VxeButton,
  VxeCheckbox,
  VxeIcon,
  VxeInput,
  VxeLoading,
  VxeModal,
  VxeNumberInput,
  VxePager,
  VxeRadioGroup,
  VxeSelect,
  VxeTooltip,
  VxeUI,
  VxeUpload,
} from 'vxe-pc-ui';

import {VxeColgroup, VxeColumn, VxeGrid, VxeTable, VxeToolbar,} from 'vxe-table';

import {usePreferences} from '#/preferences';

import { $t } from '#/locales';

// 导入默认的语言
import zhCN from 'vxe-pc-ui/lib/language/zh-CN';
import enUS from 'vxe-pc-ui/lib/language/en-US';

import { Button, Image, Popconfirm, Switch, Tag } from 'ant-design-vue';

import { IconifyIcon } from '#/icons';

import { get, isFunction, isString } from '#/utils';

import {extendsDefaultFormatter} from './extends';

import {SetupVxeTable} from "./types";

// 是否加载过
let isInit = false;

// 部分组件，如果没注册，vxe-table 会报错，这里实际没用组件，只是为了不报错，同时可以减少打包体积
const createVirtualComponent = (name = '') => {
  return defineComponent({
    name,
  });
};

export function initVxeTable() {
  if (isInit) {
    return;
  }
  VxeUI.component(VxeTable);
  VxeUI.component(VxeColumn);
  VxeUI.component(VxeColgroup);
  VxeUI.component(VxeGrid);
  VxeUI.component(VxeToolbar);
  VxeUI.component(VxeButton);
  VxeUI.component(VxeCheckbox);
  VxeUI.component(createVirtualComponent('VxeForm'));
  VxeUI.component(VxeIcon);
  VxeUI.component(VxeInput);
  VxeUI.component(VxeLoading);
  VxeUI.component(VxeModal);
  VxeUI.component(VxeNumberInput);
  VxeUI.component(VxePager);
  VxeUI.component(VxeRadioGroup);
  VxeUI.component(VxeSelect);
  VxeUI.component(VxeTooltip);
  VxeUI.component(VxeUpload);
  isInit = true;
}

export function setupVxeTable() {
  const {configVxeTable}: SetupVxeTable = {
    configVxeTable: (vxeUI) => {
      vxeUI.setConfig({
        grid: {
          align: 'center',
          border: false,
          columnConfig: {
            resizable: true,
          },
          minHeight: 180,
          formConfig: {
            // 全局禁用vxe-table的表单配置，使用formOptions
            enabled: false,
          },
          proxyConfig: {
            autoLoad: true,
            response: {
              result: 'items',
              total: 'total',
              list: 'items',
            },
            showActiveMsg: true,
            showResponseMsg: false,
          },
          round: true,
          showOverflow: true,
          size: 'small',
        } as VxeTableGridOptions,
      });

      // 解决vxeTable在热更新时可能会出错的问题
      vxeUI.renderer.forEach((_item, key) => {
        if (key.startsWith('Cell')) {
          vxeUI.renderer.delete(key);
        }
      });

      // 表格配置项可以用 cellRender: { name: 'CellImage' },
      vxeUI.renderer.add('CellImage', {
        renderTableDefault(_renderOpts, params) {
          const { column, row } = params;
          return h(Image, { src: row[column.field] });
        },
      });

      // 表格配置项可以用 cellRender: { name: 'CellLink' },
      vxeUI.renderer.add('CellLink', {
        renderTableDefault(renderOpts) {
          const { props } = renderOpts;
          return h(
              Button,
              { size: 'small', type: 'link' },
              { default: () => props?.text },
          );
        },
      });

      // 单元格渲染： Tag
      vxeUI.renderer.add('CellTag', {
        renderTableDefault({ options, props }, { column, row }) {
          const value = get(row, column.field);
          const tagOptions = options ?? [
            { color: 'success', label: $t('common.enabled'), value: 1 },
            { color: 'error', label: $t('common.disabled'), value: 0 },
          ];
          const tagItem = tagOptions.find((item) => item.value === value);
          return h(
              Tag,
              {
                ...props,
                ...objectOmit(tagItem ?? {}, ['label']),
              },
              { default: () => tagItem?.label ?? value },
          );
        },
      });

      vxeUI.renderer.add('CellSwitch', {
        renderTableDefault({ attrs, props }, { column, row }) {
          const loadingKey = `__loading_${column.field}`;
          const finallyProps = {
            checkedChildren: $t('common.enabled'),
            checkedValue: 1,
            unCheckedChildren: $t('common.disabled'),
            unCheckedValue: 0,
            ...props,
            checked: row[column.field],
            loading: row[loadingKey] ?? false,
            'onUpdate:checked': onChange,
          };
          async function onChange(newVal: any) {
            row[loadingKey] = true;
            try {
              const result = await attrs?.beforeChange?.(newVal, row);
              if (result !== false) {
                row[column.field] = newVal;
              }
            } finally {
              row[loadingKey] = false;
            }
          }
          return h(Switch, finallyProps);
        },
      });

      // 注册表格的操作按钮渲染器
      vxeUI.renderer.add('CellOperation', {
        renderTableDefault({ attrs, options, props }, { column, row }) {
          const defaultProps = { size: 'small', type: 'link', ...props };
          let align = 'end';
          switch (column.align) {
            case 'center': {
              align = 'center';
              break;
            }
            case 'left': {
              align = 'start';
              break;
            }
            default: {
              align = 'end';
              break;
            }
          }
          const presets: Recordable<Recordable<any>> = {
            delete: {
              danger: true,
              text: $t('common.delete'),
            },
            edit: {
              text: $t('common.edit'),
            },
          };
          const operations: Array<Recordable<any>> = (
              options || ['edit', 'delete']
          )
              .map((opt) => {
                if (isString(opt)) {
                  return presets[opt]
                      ? { code: opt, ...presets[opt], ...defaultProps }
                      : {
                        code: opt,
                        text: $t(`common.${opt}`) ? $t(`common.${opt}`) : opt,
                        ...defaultProps,
                      };
                } else {
                  return { ...defaultProps, ...presets[opt.code], ...opt };
                }
              })
              .map((opt) => {
                const optBtn: Recordable<any> = {};
                Object.keys(opt).forEach((key) => {
                  optBtn[key] = isFunction(opt[key]) ? opt[key](row) : opt[key];
                });
                return optBtn;
              })
              .filter((opt) => opt.show !== false);

          function renderBtn(opt: Recordable<any>, listen = true) {
            return h(
                Button,
                {
                  ...props,
                  ...opt,
                  icon: undefined,
                  onClick: listen
                      ? () =>
                          attrs?.onClick?.({
                            code: opt.code,
                            row,
                          })
                      : undefined,
                },
                {
                  default: () => {
                    const content = [];
                    if (opt.icon) {
                      content.push(
                          h(IconifyIcon, { class: 'size-5', icon: opt.icon }),
                      );
                    }
                    content.push(opt.text);
                    return content;
                  },
                },
            );
          }

          function renderConfirm(opt: Recordable<any>) {
            let viewportWrapper: HTMLElement | null = null;
            return h(
                Popconfirm,
                {
                  /**
                   * 当popconfirm用在固定列中时，将固定列作为弹窗的容器时可能会因为固定列较窄而无法容纳弹窗
                   * 将表格主体区域作为弹窗容器时又会因为固定列的层级较高而遮挡弹窗
                   * 将body或者表格视口区域作为弹窗容器时又会导致弹窗无法跟随表格滚动。
                   * 鉴于以上各种情况，一种折中的解决方案是弹出层展示时，禁止操作表格的滚动条。
                   * 这样既解决了弹窗的遮挡问题，又不至于让弹窗随着表格的滚动而跑出视口区域。
                   */
                  getPopupContainer(el) {
                    viewportWrapper = el.closest('.vxe-table--viewport-wrapper');
                    return document.body;
                  },
                  placement: 'topLeft',
                  title: $t('ui.actionTitle.delete', [attrs?.nameTitle || '']),
                  ...props,
                  ...opt,
                  icon: undefined,
                  onOpenChange: (open: boolean) => {
                    // 当弹窗打开时，禁止表格的滚动
                    if (open) {
                      viewportWrapper?.style.setProperty('pointer-events', 'none');
                    } else {
                      viewportWrapper?.style.removeProperty('pointer-events');
                    }
                  },
                  onConfirm: () => {
                    attrs?.onClick?.({
                      code: opt.code,
                      row,
                    });
                  },
                },
                {
                  default: () => renderBtn({ ...opt }, false),
                  description: () =>
                      h(
                          'div',
                          { class: 'truncate' },
                          $t('ui.actionMessage.deleteConfirm', [
                            row[attrs?.nameField || 'name'],
                          ]),
                      ),
                },
            );
          }

          const btns = operations.map((opt) =>
              opt.code === 'delete' ? renderConfirm(opt) : renderBtn(opt),
          );
          return h(
              'div',
              {
                class: 'flex table-operations',
                style: { justifyContent: align },
              },
              btns,
          );
        },
      });

      // 这里可以自行扩展 vxe-table 的全局配置，比如自定义格式化
      // vxeUI.formats.add
    }
  };

  initVxeTable();

  const { isDark, locale } = usePreferences();

  const localMap = {
    'zh-CN': zhCN,
    'en-US': enUS,
  };

  watch(
      [() => isDark.value, () => locale.value],
      ([isDarkValue, localeValue]) => {
        VxeUI.setTheme(isDarkValue ? 'dark' : 'light');
        VxeUI.setI18n(localeValue, localMap[localeValue]);
        VxeUI.setLanguage(localeValue);
      },
      {
        immediate: true,
      },
  );

  extendsDefaultFormatter(VxeUI);

  configVxeTable(VxeUI);
}